`include "defines.v"

module mips(
    input  wire               clock,
	input  wire               reset,
	input  wire[`RegisterBus] rom_data_input,
	output wire[`RegisterBus] rom_address_output,
	output wire               rom_ce_output
);

    wire[`AddressBus]         pc;
	wire[`AddressBus]         id_pc_input;
	wire[`DataBus]            id_instruction_input;
	
	wire[`ALUOpBus]           id_aluop_output;
	wire[`ALUSelBus]          id_alusel_output;
	wire[`RegisterBus]        id_reg1_output;
	wire[`RegisterBus]        id_reg2_output;
	wire                      id_wreg_output;
	wire[`RegisterAddressBus] id_wd_output;
	
	wire[`ALUOpBus]           ex_aluop_input;
	wire[`ALUSelBus]          ex_alusel_input;
	wire[`RegisterBus]        ex_reg1_input;
	wire[`RegisterBus]        ex_reg2_input;
	wire                      ex_wreg_input;
	wire[`RegisterAddressBus] ex_wd_input;
	
	wire                      ex_wreg_output;
	wire[`RegisterAddressBus] ex_wd_output;
	wire[`RegisterBus]        ex_wdata_output;
	
	wire                      mem_wreg_input;
	wire[`RegisterAddressBus] mem_wd_input;
	wire[`RegisterBus]        mem_wdata_input;
	
	wire                      mem_wreg_output;
	wire[`RegisterAddressBus] mem_wd_output;
	wire[`RegisterBus]        mem_wdata_output;

	wire                      wb_wreg_input;
	wire[`RegisterAddressBus] wb_wd_input;
	wire[`RegisterBus]        wb_wdata_input;
	
	wire                      reg1_read;
	wire                      reg2_read;
	wire[`RegisterBus]        reg1_data;
	wire[`RegisterBus]        reg2_data;
	wire[`RegisterAddressBus] reg1_address;
	wire[`RegisterAddressBus] reg2_address;
	
	wire[`RegisterBus] ex_hi_in;
	wire[`RegisterBus] ex_lo_in;


	wire ex_hilo_we_o;
	wire[`RegisterBus]  ex_hi_o;
	wire[`RegisterBus]  ex_lo_o;

	wire 		  mem_hilo_we_in;
	wire[`RegisterBus] mem_hi_in;
	wire[`RegisterBus] mem_lo_in;

	wire		    mem_hilo_we;
	wire[`RegisterBus] mem_hi_o;
	wire[`RegisterBus] mem_lo_o;

	wire        wb_hilo_en;
	wire[`RegisterBus] wb_hi_o;
	wire[`RegisterBus] wb_lo_o;
	wire[`STALL_BUS] stall_b;
	wire 			stall_req_id;
	wire			stall_req_ex;
	wire			div_sign_i;
	wire			div_start_i;
	wire			div_res_ready;
	wire[`RegisterBus]			div_1_i;
	wire[`RegisterBus]			div_2_i;
	wire[`DoubleRegisterBus]	div_res_i;
	wire						branch_sign;
	wire[`RegisterBus]			branch_addr;
	wire						id_ds_in;
	wire						id_ds_o;
	wire[`RegisterBus]			link_addr_id_o;
	wire						next_ds_id;
	wire[`RegisterBus]			link_addr_ex_i;
	wire						ex_is_ds_i;
	wire						id_ds_in;

	pc_reg pc_reg0(
	    .clock(clock), .reset(reset),
		.pc(pc), .ce(rom_ce_output),.stall(stall_b),.branch_address(branch_addr),
		.branch_sig(branch_sign)
	);
	
	assign rom_address_output = pc;

	if_id if_id0(
	    .clock(clock), .reset(reset),
		.if_pc(pc), .if_instruction(rom_data_input),
		.id_pc(id_pc_input), .id_instruction(id_instruction_input),.stall(stall_b)
	);
	
	id id0(
	    .reset(reset),
		.pc_input(id_pc_input), .instruction_input(id_instruction_input),
		.reg1_data_input(reg1_data), .reg2_data_input(reg2_data),
		.reg1_read_output(reg1_read), .reg2_read_output(reg2_read),
		.reg1_addr_output(reg1_address), .reg2_addr_output(reg2_address),
		.aluop_output(id_aluop_output), .alusel_output(id_alusel_output),
		.reg1_output(id_reg1_output), .reg2_output(id_reg2_output),
		.wd_output(id_wd_output), .wreg_output(id_wreg_output),
		.ex_wdata_i(ex_wdata_output),.ex_regd_i(ex_wd_output),.ex_regw_i(ex_wreg_output),
        .mem_wdata_i(mem_wdata_output),.mem_regd_i(mem_wd_output),.mem_regw_i(mem_wreg_output),
		.stall_req(stall_req_id),.branch_sign_o(branch_sign),.branch_addr_o(branch_addr),
		.is_in_ds_i(id_ds_in),.is_in_ds_o(id_ds_o),.link_addr_o(link_addr_id_o),.next_in_ds_o(next_ds_id)
	);
	
	regfile regfile1(
        .clock(clock), .reset(reset),
		.write_enable(wb_wreg_input), .write_address(wb_wd_input), .write_data(wb_wdata_input),
		.read_enable1(reg1_read), .read_address1(reg1_address), .read_data1(reg1_data),
		.read_enable2(reg2_read), .read_address2(reg2_address), .read_data2(reg2_data)
	);
	
	id_ex id_ex0(
        .clock(clock), .reset(reset),
		.id_aluop(id_aluop_output), .id_alusel(id_alusel_output),
		.id_reg1(id_reg1_output), .id_reg2(id_reg2_output),
		.id_wd(id_wd_output), .id_wreg(id_wreg_output),
		
		.ex_aluop(ex_aluop_input), .ex_alusel(ex_alusel_input),
		.ex_reg1(ex_reg1_input), .ex_reg2(ex_reg2_input),
		.ex_wd(ex_wd_input), .ex_wreg(ex_wreg_input),.stall(stall_b),
		.link_addr_id(link_addr_id_o),.is_in_ds_id(id_ds_o),.next_in_ds_id(next_ds_id),
		.link_addr_ex(link_addr_ex_i),.is_in_ds_ex(ex_is_ds_i),.is_in_ds_o(id_ds_in)
	);
	
	ex ex0(
	    .reset(reset),
		.aluop_input(ex_aluop_input), .alusel_input(ex_alusel_input),
		.reg1_input(ex_reg1_input), .reg2_input(ex_reg2_input),
		.wd_input(ex_wd_input), .wreg_input(ex_wreg_input),
		.wd_output(ex_wd_output), .wreg_output(ex_wreg_output), .wdata_output(ex_wdata_output),
		.hi_input(ex_hi_in),.lo_input(ex_lo_in),.mem_hi_input(mem_hi_o),
		.mem_lo_input(mem_lo_o),.mem_hilo_we(mem_hilo_we),
		.wb_hilo_we(wb_hilo_en),.wb_hi_input(wb_hi_o),.wb_lo_input(wb_lo_o),
		.hi_o(ex_hi_o),.lo_o(ex_lo_o),.hilo_we(ex_hilo_we_o),.div_op1(div_1_i),
		.div_op2(div_2_i),.div_start(div_start_i),.div_sign(div_sign_i),.div_res(div_res_i),
		.div_done(div_res_ready),.stall_req(stall_req_ex),
		.link_addr_i(link_addr_ex_i),.is_in_ds_i(ex_is_ds_i)
	);
	
	ex_mem ex_mem0(
	    .clock(clock), .reset(reset),
		.ex_wd(ex_wd_output), .ex_wreg(ex_wreg_output), .ex_wdata(ex_wdata_output),
		.mem_wd(mem_wd_input), .mem_wreg(mem_wreg_input), .mem_wdata(mem_wdata_input),
		.ex_hi(ex_hi_o),.ex_lo(ex_lo_o),.ex_hilo_we(ex_hilo_we_o),.mem_hi(mem_hi_in),
		.mem_lo(mem_lo_in),.mem_hilo_we(mem_hilo_we_in),.stall(stall_b)
	);
	
	
	mem mem0(
	    .reset(reset),
		.wd_input(mem_wd_input), .wreg_input(mem_wreg_input), .wdata_input(mem_wdata_input),
		.wd_output(mem_wd_output), .wreg_output(mem_wreg_output), .wdata_output(mem_wdata_output),
		.hi_input(mem_hi_in),.lo_input(mem_lo_in),.hilo_we(mem_hilo_we_in),.hi_o(mem_hi_o),
		.lo_o(mem_lo_o),.hilo_we_o(mem_hilo_we)
	);
	
	mem_wb mem_wb0(
	    .clock(clock), .reset(reset),
		.mem_wd(mem_wd_output), .mem_wreg(mem_wreg_output), .mem_wdata(mem_wdata_output),
		.wb_wd(wb_wd_input), .wb_wreg(wb_wreg_input), .wb_wdata(wb_wdata_input),.mem_hi(mem_hi_o),
		.mem_lo(mem_lo_o),.mem_hilo_we(mem_hilo_we),.wb_hilo_we(wb_hilo_en),.wb_hi(wb_hi_o),
		.wb_lo(wb_lo_o),.stall(stall_b)
	);
	hilo_reg hilo_reg0(
		.clk(clock),.rst(reset),.wr_en(wb_hilo_en),.hi_input(wb_hi_o),.hi_o(ex_hi_in),
		.lo_input(wb_lo_o),.lo_o(ex_lo_in)
	);
	stall stall0(
		.rst(reset),.req_ex(stall_req_ex),.req_id(stall_req_id),.stall_res(stall_b)
	);
	div_m div_m0(
		.reset(reset),.clock(clock),.is_sign_div_input(div_sign_i),
		.div_data1_input(div_1_i),.div_data2_input(div_2_i),
		.div_start_input(div_start_i),.div_cancel_input(1'b0),.div_result_output(div_res_i),
		.div_ready_output(div_res_ready)
	);

endmodule